package com.gao.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

//懒汉式单例
public class LazyMan {

    private static boolean gaozong = false;

    private LazyMan(){

        synchronized (LazyMan.class){
//            if (lazyMan != null){
//                throw new RuntimeException("不要试图使用反射破坏单例 ");
//            }
            if (gaozong == false){
                gaozong = true;
            }else {
                throw new RuntimeException("不要试图使用反射破坏单例 ");
            }
        }

        System.out.println(Thread.currentThread().getName() + "启动");
    }

//    必须加上volatile
    private volatile static LazyMan lazyMan;


    public static LazyMan getInstance(){

//        加锁
//        双重检测锁模式的懒汉式单例 DCL
        if(lazyMan == null){
            synchronized (LazyMan.class){
                if (lazyMan == null){
//                    不是一个原子性操作
                    lazyMan = new LazyMan();

                    /**
                     * 1、 分配内存空间
                     * 2、 执行构造方法初始化对象
                     * 3、 把这个对象指向这个空间
                     * 指令重排发生！
                     * 123
                     * 132  A
                     *      B
                     */

                }
            }
        }
//        此时lazyMan没有完成构造 内存空间是虚无的
        return lazyMan;
    }

//    单线程下确实OK，但是并发下呢？

//    public static void main(String[] args) {
//        for (int i = 1; i <= 10 ; i++) {
//            new Thread(() -> {
//                lazyMan.getInstance();
//            }).start();
//        }
//    }

//    反射！
    public static void main(String[] args) throws Exception {
//        LazyMan instance1 = LazyMan.getInstance();

        Field gaozong1 = LazyMan.class.getDeclaredField("gaozong");
        gaozong1.setAccessible(true );

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyMan instance2 = declaredConstructor.newInstance();

        gaozong1.set(instance2,false);

        LazyMan instance1 = declaredConstructor.newInstance();

        System.out.println(instance1);
        System.out.println(instance2);
        System.out.println(instance1 == instance2);

//        com.gao.single.LazyMan@74a14482
//        com.gao.single.LazyMan@1540e19d
//        反射可以破坏这种单例
    }
}
